/*!
    \file    main.c
    \brief   USART DMA transmitter receiver
    
    \version 2024-01-17, V2.6.4, demo for GD32F4xx
*/
#include "bs_app_conf.h"
#include "gd32f4xx.h"
#include <stdio.h>
#include <stdlib.h>
#include "gd32f470i_eval.h"
#include "systick.h"

#include "bs_app.h"
#include "bs_protocol.h"

#include "drv_usb_hw.h"
#include "cdc_acm_core.h"
#include "dev_flash.h" 

#define LOG_TAG        "[ICE]"
#include "log.h"

#define TIMER1_CH1CV                      ((uint32_t)(TIMER1 + 0x38))
#define TIMER2_CH0CV                      ((uint32_t)(TIMER2 + 0x34))


usb_core_driver cdc_acm;

bs_writer_ctx_t bs_ctx_ch0;
bs_writer_ctx_t bs_ctx_ch1;

struct S_Writer m_app;
uint32_t recvTotal;

int bs_jiffies = 0;
uint32_t g_debug_level = 4;

bs_led_dev_t led_ok = {.port = GPIOA, .pin = GPIO_PIN_2};
bs_led_dev_t led_ng = {.port = GPIOA, .pin = GPIO_PIN_1};

FATFS ffs;

void timer_compare_config(void);
void gpio_config(void);
void debug_com_init(void);
void timer_dma_config(void);

void nvic_config(void);
void timer_one_pulse_config(void);

void ice_spi_init(void);


/*!
    \brief      main function
    \param[in]  none
    \param[out] none
    \retval     none
*/
int main(void){
    /* configure systick */
    systick_config();
    nvic_config();
    gpio_config();

    fmc_state_get();
    fmc_flag_clear(FMC_FLAG_PGSERR);
    fmc_state_get();

    /* enable DMA clock */
    rcu_periph_clock_enable(RCU_DMA0);
    rcu_periph_clock_enable(RCU_DMA1);

    /* uart printf port */
    debug_com_init();

    /* configure usb CDC device */
    usb_gpio_config();
    usb_rcu_config();

#ifdef USE_USB_FS
    usbd_init (&cdc_acm, USB_CORE_ENUM_FS, &cdc_desc, &cdc_class);
#elif defined(USE_USB_HS)
    usbd_init (&cdc_acm, USB_CORE_ENUM_HS, &cdc_desc, &cdc_class);
#endif
    usb_intr_config();
		
    printf("\r\n\r\n********* power on *********\r\n\r\n");
    rtc_show_time();

    /* configure SPI FLASH */
    spi_flash_init();
    bs_sf_device_init();
    bs_dev_lcd_init();

    /* configure TIMER Output Compare */
    timer_compare_config();
    timer_one_pulse_config();

    ice_spi_init();

    /* initial user button */
    key_module_init();
    bs_dev_buz_init();
    bs_dev_buz_ctl(BEEP_1);

    /* mount fs */
    GPIO_BOP(GPIOB) = GPIO_PIN_0;
    f_mount(0, &ffs);
    GPIO_BC(GPIOB) = GPIO_PIN_0;
    // f_mkfs(0);
    // bs_imgr_region_clear();
    
    // jf_delete();
    // bs_write_bkp_reg(1, 0x1000);

    /* initial image files info */
    bs_imgr_init();

    /* backup domain register */
    printf("BKP register1: %d\n", bs_read_bkp_reg(1));

    bs_comm_init();
    while(USBD_CONFIGURED != cdc_acm.dev.cur_status);
    usb_cdc_handler *cdc = cdc_acm.dev.class_data[CDC_COM_INTERFACE];

    while(1){
        // timer_channel_output_state_config(TIMER0, TIMER_CH_1, TIMER_CCX_ENABLE);
        // bs_lcd_process();
        bs_writer_test(&bs_ctx_ch0);
        bs_writer_test(&bs_ctx_ch1);

        if(cdc->receive_length > 0){
            recvTotal = circ_buf_write(&m_app.m_circ_buffer, cdc->data, cdc->receive_length);
            cdc->receive_length = 0U;
        }

        if (USBD_CONFIGURED == cdc_acm.dev.cur_status) {
            if (0U == cdc_acm_check_ready(&cdc_acm)) {
                cdc_acm_data_receive(&cdc_acm);
            } else {
                // cdc_acm_data_send(&cdc_acm);
            }
        }
        bs_comm_process();
        bs_key_process();
        bs_led_process();
        // bs_spiflash_process();

  }
}


/*!
    \brief      configure the nested vectored interrupt controller
    \param[in]  none
    \param[out] none
    \retval     none
*/
void nvic_config(void)
{
    nvic_priority_group_set(NVIC_PRIGROUP_PRE1_SUB3);
    nvic_irq_enable(TIMER0_UP_TIMER9_IRQn, 0, 1);
    nvic_irq_enable(TIMER7_UP_TIMER12_IRQn, 0, 1);

    // spi flash
    nvic_irq_enable(DMA1_Channel5_IRQn, 0, 2);
    // nvic_irq_enable(TIMER1_IRQn, 0, 1);
}


/*!
    \brief      configure the GPIO ports
    \param[in]  none
    \param[out] none
    \retval     none
*/
void gpio_config(void)
{
    rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_GPIOB);
    rcu_periph_clock_enable(RCU_GPIOC);
    rcu_periph_clock_enable(RCU_GPIOD);
    rcu_periph_clock_enable(RCU_GPIOE);
    rcu_periph_clock_enable(RCU_GPIOF);

#ifndef PWM_SINGLE_PULSE_MODE
    /* configure PA1(TIMER1 CH1) as alternate function*/
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_1);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_1);
    gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_1);
#else
    /* LED1 PA1 */
    gpio_bit_set(GPIOA, GPIO_PIN_1|GPIO_PIN_2);
    gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_1|GPIO_PIN_2);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_1|GPIO_PIN_2);
#endif

    /* configure PA6(TIMER2 CH0) as alternate function*/
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_6);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
    gpio_af_set(GPIOA, GPIO_AF_2, GPIO_PIN_6);

    /* configure PE11(TIMER0 CH1) as alternate function*/
    gpio_mode_set(GPIOE, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_11);
    gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_11);
    gpio_af_set(GPIOE, GPIO_AF_1, GPIO_PIN_11);
 
    /* configure PC7(TIMER7 CH1) as alternate function*/
    gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_7);
    gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_7);
    gpio_af_set(GPIOC, GPIO_AF_3, GPIO_PIN_7);
 
    /* configure debug pin */
    gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_0|GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8);
    gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_0|GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8);

    /* configure usart6 TX PE8 */
    gpio_mode_set(GPIOE, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_8);
    gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_8);
    gpio_af_set(GPIOE, GPIO_AF_8, GPIO_PIN_8);

    /* configure PD12 TIMER3_CH0 */
    gpio_mode_set(GPIOD, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_12);
    gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_12);
    gpio_af_set(GPIOD, GPIO_AF_2, GPIO_PIN_12);
}


/*!
    \brief      configure COM port
    \param[in]  COM: COM on the board
    \param[out] none
    \retval     none
*/
void debug_com_init()
{
    /* USART configure */
    uint32_t com = WRITER_PRINT_COM;
    rcu_periph_clock_enable(RCU_UART6);
    usart_deinit(com);
    usart_baudrate_set(com,115200U);
    usart_parity_config(com, USART_PM_NONE);
    usart_word_length_set(com, USART_WL_8BIT);
    usart_stop_bit_set(com, USART_STB_1BIT);
    // usart_receive_config(com, USART_RECEIVE_ENABLE);
    usart_transmit_config(com, USART_TRANSMIT_ENABLE);
    usart_enable(com);
}


/*!
    \brief      configure USART DMA
    \param[in]  none
    \param[out] none
    \retval     none
*/
void timer_dma_config(void)
{
#ifndef PWM_SINGLE_PULSE_MODE
    extern uint32_t ice_clk0_buff[];
    extern uint32_t ice_clk1_buff[];
    dma_single_data_parameter_struct dma_init_struct;

    /* enable DMA clock */
    rcu_periph_clock_enable(RCU_DMA0);
    rcu_periph_clock_enable(RCU_DMA1);

    /* initialize DMA channel1 */
    dma_deinit(DMA0, DMA_CH1);

    /* DMA channel1 initialize */
    dma_init_struct.periph_addr = TIMER1_CH1CV;
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.memory0_addr = (uint32_t)ice_clk0_buff;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_32BIT;
    dma_init_struct.circular_mode = DMA_CIRCULAR_MODE_DISABLE;   // DMA_CIRCULAR_MODE_DISABLE
    dma_init_struct.direction = DMA_MEMORY_TO_PERIPH;
    dma_init_struct.number = 9;
    dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
    dma_single_data_mode_init(DMA0, DMA_CH1, &dma_init_struct);
    dma_channel_subperipheral_select(DMA0, DMA_CH1, DMA_SUBPERI3);

    /* enable DMA channel1 */
    dma_channel_enable(DMA0, DMA_CH1);

    /* initialize DMA channel2 */
    dma_deinit(DMA0, DMA_CH2);

    /* DMA channel2 initialize */
    dma_init_struct.periph_addr = TIMER2_CH0CV;
    dma_init_struct.memory0_addr = (uint32_t)ice_clk1_buff;
    dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_32BIT;
    dma_single_data_mode_init(DMA0, DMA_CH2, &dma_init_struct);
    dma_channel_subperipheral_select(DMA0, DMA_CH2, DMA_SUBPERI5);

    /* enable DMA channel2 */
    dma_channel_enable(DMA0, DMA_CH2);
#endif
}


/*!
    \brief      initialize timer output compare
    \param[in]  none
    \param[out] none
    \retval     none
*/
void timer_compare_config(void)
{
#ifndef PWM_SINGLE_PULSE_MODE
    timer_parameter_struct timer_initpara;
    timer_oc_parameter_struct timer_ocintpara;

    rcu_periph_clock_enable(RCU_TIMER1);
    rcu_periph_clock_enable(RCU_TIMER2);
    rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4);

    timer_deinit(TIMER1);

    /* TIMER1 configuration */
    timer_initpara.prescaler         = 0;
    timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;
    timer_initpara.counterdirection  = TIMER_COUNTER_UP;
    timer_initpara.period            = ICE_PERIOD-1;
    timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;
    timer_initpara.repetitioncounter = 0;
    timer_init(TIMER1,&timer_initpara);

    /* CH1 configuration in OC TOGGLE mode */
    timer_ocintpara.ocpolarity  = TIMER_OC_POLARITY_HIGH;
    timer_ocintpara.outputstate = TIMER_CCX_ENABLE;
    timer_ocintpara.ocnpolarity  = TIMER_OCN_POLARITY_HIGH;
    timer_ocintpara.outputnstate = TIMER_CCXN_DISABLE;
    timer_ocintpara.ocidlestate  = TIMER_OC_IDLE_STATE_LOW;
    timer_ocintpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
    timer_channel_output_config(TIMER1, TIMER_CH_1, &timer_ocintpara);

    timer_channel_output_pulse_value_config(TIMER1, TIMER_CH_1, 0);
    timer_channel_output_mode_config(TIMER1, TIMER_CH_1, TIMER_OC_MODE_PWM0);
    timer_channel_output_shadow_config(TIMER1, TIMER_CH_1, TIMER_OC_SHADOW_ENABLE);

    /* auto-reload preload enable */
    timer_auto_reload_shadow_enable(TIMER1);
    timer_enable(TIMER1);
    // timer_interrupt_enable(TIMER1,TIMER_INT_UP);
    // /* TIMER0 update DMA request enable */
    // timer_dma_enable(TIMER0, TIMER_DMA_UPD);

    timer_deinit(TIMER2);

    /* TIMER2 configuration */
    timer_init(TIMER2,&timer_initpara);

    /* CH1 configuration in OC TOGGLE mode */
    timer_channel_output_config(TIMER2, TIMER_CH_0, &timer_ocintpara);

    timer_channel_output_pulse_value_config(TIMER2, TIMER_CH_0, 0);
    timer_channel_output_mode_config(TIMER2, TIMER_CH_0, TIMER_OC_MODE_PWM0);
    timer_channel_output_shadow_config(TIMER2, TIMER_CH_0, TIMER_OC_SHADOW_ENABLE);

    /* auto-reload preload enable */
    timer_auto_reload_shadow_enable(TIMER2);
    timer_enable(TIMER2);
#endif
}


/*!
    \brief
    \param[in]  none
    \param[out] none
    \retval     none
*/
void ice_spi_init()
{
    spi_i2s_deinit(SPI0);
    spi_i2s_deinit(SPI1);
    rcu_periph_clock_enable(RCU_GPIOB);
    rcu_periph_clock_enable(RCU_GPIOE);
    rcu_periph_clock_enable(RCU_SPI1);
    rcu_periph_clock_enable(RCU_SPI0);

    /* configure SPI0 GPIO */
    /* CLK MISO MOSI */
    gpio_af_set(GPIOB, GPIO_AF_5, GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5);
    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE,  GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5);
    gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5);

    /* configure SPI1 GPIO */
    /* CLK MISO MOSI */
    gpio_af_set(GPIOB, GPIO_AF_5, GPIO_PIN_10 | GPIO_PIN_14 | GPIO_PIN_15);
    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_10 | GPIO_PIN_14 | GPIO_PIN_15);
    gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_10 | GPIO_PIN_14 | GPIO_PIN_15);

    spi_parameter_struct spi_init_struct;

    /* configure SPI0 parameter */
    spi_init_struct.trans_mode           = SPI_TRANSMODE_BDTRANSMIT; // SPI_TRANSMODE_FULLDUPLEX
    spi_init_struct.device_mode          = SPI_SLAVE;
    spi_init_struct.frame_size           = SPI_FRAMESIZE_8BIT;
    spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
    spi_init_struct.nss                  = SPI_NSS_SOFT;
    spi_init_struct.prescale             = SPI_PSC_32;
    spi_init_struct.endian               = SPI_ENDIAN_LSB;
    spi_init(SPI0, &spi_init_struct);

    /* configure SPI1 parameter */
    spi_init_struct.trans_mode           = SPI_TRANSMODE_BDTRANSMIT;  // 
    spi_init_struct.device_mode          = SPI_SLAVE;
    spi_init_struct.frame_size           = SPI_FRAMESIZE_8BIT;
    spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
    spi_init_struct.nss                  = SPI_NSS_SOFT;
    spi_init_struct.prescale             = SPI_PSC_32;
    spi_init_struct.endian               = SPI_ENDIAN_LSB;
    spi_init(SPI1, &spi_init_struct);

    spi_nss_internal_high(SPI0);
    spi_enable(SPI0);
    spi_nss_internal_low(SPI0);

    spi_nss_internal_high(SPI1);
    spi_enable(SPI1);
    spi_nss_internal_low(SPI1);
}


/*!
    \brief      configure timer one pulse mode
    \param[in]  none
    \param[out] none
    \retval     none
*/
void timer_one_pulse_config()
{
    timer_parameter_struct timer_initpara;
    timer_oc_parameter_struct timer_ocintpara;

    rcu_periph_clock_enable(RCU_TIMER0);
    rcu_periph_clock_enable(RCU_TIMER7);
    rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4);

    timer_deinit(TIMER0);

    /* TIMER0 configuration */
    timer_initpara.prescaler         = 0;
    timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;
    timer_initpara.counterdirection  = TIMER_COUNTER_UP;
    timer_initpara.period            = ICE_PERIOD-1;
    timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;
    timer_initpara.repetitioncounter = 8-1;
    timer_init(TIMER0, &timer_initpara);

    /* CH1 configuration in OC TOGGLE mode */
    timer_ocintpara.ocpolarity  = TIMER_OC_POLARITY_HIGH;
    timer_ocintpara.outputstate = TIMER_CCX_ENABLE;
    timer_ocintpara.ocnpolarity  = TIMER_OCN_POLARITY_HIGH;
    timer_ocintpara.outputnstate = TIMER_CCXN_DISABLE;
    timer_ocintpara.ocidlestate  = TIMER_OC_IDLE_STATE_LOW;
    timer_ocintpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
    timer_channel_output_config(TIMER0, TIMER_CH_1, &timer_ocintpara);

    timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_1, TIMER1_PWM_DUTY);
    timer_channel_output_mode_config(TIMER0, TIMER_CH_1, TIMER_OC_MODE_PWM1);
    timer_channel_output_shadow_config(TIMER0, TIMER_CH_1, TIMER_OC_SHADOW_ENABLE);

    /* single pulse mode selection */
    timer_single_pulse_mode_config(TIMER0, TIMER_SP_MODE_SINGLE);

    timer_primary_output_config(TIMER0,ENABLE);
    /* auto-reload preload enable */
    timer_auto_reload_shadow_enable(TIMER0);
    timer_disable(TIMER0);
    timer_interrupt_flag_clear(TIMER0, TIMER_INT_FLAG_UP);
    // timer_enable(TIMER0);

    timer_deinit(TIMER7);
    timer_init(TIMER7, &timer_initpara);

    /* CH1 configuration in OC TOGGLE mode */
    timer_ocintpara.ocpolarity  = TIMER_OC_POLARITY_HIGH;
    timer_ocintpara.outputstate = TIMER_CCX_ENABLE;
    timer_ocintpara.ocnpolarity  = TIMER_OCN_POLARITY_HIGH;
    timer_ocintpara.outputnstate = TIMER_CCXN_DISABLE;
    timer_ocintpara.ocidlestate  = TIMER_OC_IDLE_STATE_LOW;
    timer_ocintpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
    timer_channel_output_config(TIMER7, TIMER_CH_1, &timer_ocintpara);

    timer_channel_output_pulse_value_config(TIMER7, TIMER_CH_1, TIMER1_PWM_DUTY);
    timer_channel_output_mode_config(TIMER7, TIMER_CH_1, TIMER_OC_MODE_PWM1);
    timer_channel_output_shadow_config(TIMER7, TIMER_CH_1, TIMER_OC_SHADOW_ENABLE);

    /* single pulse mode selection */
    timer_single_pulse_mode_config(TIMER7, TIMER_SP_MODE_SINGLE);

    timer_primary_output_config(TIMER7,ENABLE);
    /* auto-reload preload enable */
    timer_auto_reload_shadow_enable(TIMER7);
    timer_disable(TIMER7);
    timer_interrupt_flag_clear(TIMER7, TIMER_INT_FLAG_UP);
    // timer_enable(TIMER7);
    return;
}


/*!
    \brief      memory compare function
    \param[in]  src: source data pointer
    \param[in]  dst: destination data pointer
    \param[in]  length: the compare data length
    \param[out] none
    \retval
*/
int memory_compare(uint8_t* src, uint8_t* dst, uint16_t length) 
{
    while(length --){
        if(*src++ != *dst++)
            return -1;
    }
    return 0;
}


/* retarget the C library printf function to the USART */
int fputc(int ch, FILE *f)
{
    usart_data_transmit(WRITER_PRINT_COM,(uint8_t)ch);
    while (RESET == usart_flag_get(WRITER_PRINT_COM, USART_FLAG_TC));
    return ch;
}


/*!
    \brief      send CDC ACM data
    \param[in]  none
    \param[out] none
    \retval     none
*/
int cdc_transmit_package(uint8_t *data, uint32_t size)
{
    usb_dev *udev = &cdc_acm;
    usb_cdc_handler *cdc = (usb_cdc_handler *)udev->dev.class_data[CDC_COM_INTERFACE];

    cdc->packet_sent = 0U;
    usbd_ep_send (udev, CDC_DATA_IN_EP, (uint8_t*)data, size);
    return 0;
}


/*!
    \brief      recv CDC ACM data continuously
    \param[in]  none
    \param[out] none
    \retval     none
*/
int cdc_receive_continue()
{
    usb_dev *udev = &cdc_acm;
    if (udev->dev.class_data[CDC_COM_INTERFACE] != NULL) {
        usb_cdc_handler *cdc = (usb_cdc_handler *)udev->dev.class_data[CDC_COM_INTERFACE];\
        if (1U == cdc->packet_receive) {
            cdc_acm_data_receive(&cdc_acm);
        }
    }
    return 0;
}


char *fmware_name;
uint32_t key_msg = 0;
int bs_units_test(uint8_t msg);

int ice_download_start()
{
    bs_led_ctl(&led_ok, LED_OFF, 0);
    bs_led_ctl(&led_ng, LED_OFF, 0);

    spi_disable(SPI0);
    spi_enable(SPI0);
    spi_nss_internal_high(SPI0);
    spi_nss_internal_low(SPI0);

    spi_disable(SPI1);
    spi_enable(SPI1);
    spi_nss_internal_high(SPI1);
    spi_nss_internal_low(SPI1);

    if (bs_writer_init(&bs_ctx_ch0, 0) == 0) {
        bs_ctx_ch0.schedu = LINKING;
        bs_ctx_ch0.int_point = 0x0186;
    } else {
        LOGI("CH0 initial error");
    }
		return 0;
}

// static char *imageList[4] = {"main_s12.o", "main_s01.o", "mainturn.o", "main_br2.o"};
#if LCD_EN == 0
#if 1
void bs_key_onclick_cb(bs_key_t *key)
{
    rtc_show_time();
    uint32_t tmp_u32;
    if (bs_units_test(key->id)) return;
    switch(key->id) {
        case 0:
            // return;
            // fmware_name = "";
            // fmware_name = "main_s01.o";
            bs_led_ctl(&led_ok, LED_OFF, 0);
            bs_led_ctl(&led_ng, LED_OFF, 0);

            spi_disable(SPI0);
            spi_enable(SPI0);
            spi_nss_internal_high(SPI0);
            spi_nss_internal_low(SPI0);

            spi_disable(SPI1);
            spi_enable(SPI1);
            spi_nss_internal_high(SPI1);
            spi_nss_internal_low(SPI1);

            if (bs_writer_init(&bs_ctx_ch0, 0) == 0) {
                bs_ctx_ch0.schedu = LINKING;
                bs_ctx_ch0.int_point = 0x0186;
            } else {
                LOGI("CH0 initial error");
            }

            // bs_writer_init(&bs_ctx_ch1, 1);
            // bs_ctx_ch1.schedu = LINKING;
            bs_ctx_ch1.int_point = 396;
        break;

        case 1:
            key_msg++;
            if (key_msg == 5)key_msg = 0;
            // bs_imgr_select_image(key_msg);
            bs_dev_buz_ctl(key_msg);
        break;

        case 2:
            __NOP();

        default:
        break;
    }
    
}
#endif
#else





#endif

/*!
    \brief      delay us
    \param[in]  us
    \param[out] none
    \retval     none
*/
// void delay_1us(int us) 
// {
//     us = us*50;
//     while(us--) {__NOP();}
// }
